package controller

import (
	"encoding/json"
	"fmt"
	. "gin-chat/router/pojo"
	"gin-chat/service"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"net/http"
	"strconv"
)

var upGrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		upgrade := websocket.IsWebSocketUpgrade(r)
		return upgrade
	},
}

//将连接统一管理，放入池子，编号，一对一聊天需要发送到对应的编号
//群聊，信息统一发给所有在线的连接

//连接信息
type Connection struct {
	Id     int64
	Client *websocket.Conn
	Send   chan []byte
}

//连接管理
type ConnectionManager struct {
	Clients   map[int64]*Connection
	Broadcast chan []byte      //广播信息
	Register  chan *Connection //注册
	Logout    chan *Connection //退出
}

var Manager = ConnectionManager{
	Clients:   make(map[int64]*Connection),
	Broadcast: make(chan []byte),
	Register:  make(chan *Connection),
	Logout:    make(chan *Connection),
}

func Init(c *gin.Context) {
	id, _ := strconv.ParseInt(c.Query("id"), 10, 64)
	session := sessions.Default(c)
	get := session.Get("sessionId")

	fmt.Println("id===", id)
	fmt.Println("get id===", get)
	client, err := upGrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		fmt.Println("Upgrade err ", err)
	}
	connection := &Connection{
		Id:     get.(int64),
		Client: client,
		Send:   make(chan []byte),
	}
	go connection.Broadcast()
	//check 用户是否还在线 不能重复加入
	Manager.Register <- connection //新用户加入
	//1.接收信息
	go connection.Read()
	//2.发送信息
	go connection.Write()
	//3.对接收的消息进行处理，根据类型放入对应通道

}

//读取数据
func (c *Connection) Read() {
	defer func() {
		fmt.Println("Read defer 结束 链接")
		Manager.Logout <- c
	}()
	for {
		_, message, err := c.Client.ReadMessage()
		fmt.Println("获取到消息", string(message))
		if err != nil {
			fmt.Println("获取消息错误", err)
			return
		}
		Manager.Broadcast <- message //一对一聊天，可以判断人员传输的号码，群聊进行群聊推送
	}
}

func (c *Connection) Write() {
	defer func() {
		fmt.Println("Write defer 结束 链接")
		Manager.Logout <- c
	}()
	for {
		select {
		case message, ok := <-c.Send:
			fmt.Println("推送消息", string(message))
			if !ok {
				c.Client.WriteMessage(websocket.CloseMessage, []byte{})
			}
			c.Client.WriteMessage(websocket.TextMessage, message)
		}
	}
}

//数据广播
func (c *Connection) Broadcast() {
	for {
		select {
		case connection := <-Manager.Register:
			Manager.Clients[connection.Id] = connection
			jsonMessage, _ := json.Marshal(&Message{
				Recipient: connection.Id,
				Content:   "连接成功 新用户",
			})
			fmt.Println("连接成功 新用户")
			connection.Send <- jsonMessage
		case connection := <-Manager.Logout:
			jsonMessage, _ := json.Marshal(&Message{
				Content: "退出成功",
			})
			fmt.Println("退出成功")
			connection.Send <- jsonMessage
			connection.Client.Close()
			delete(Manager.Clients, connection.Id)
		case broadcast := <-Manager.Broadcast:
			var messageStrut Message
			json.Unmarshal(broadcast, &messageStrut)
			fmt.Println("broadcast ===", string(broadcast))
			fmt.Printf("broadcast 消息广播%+v\n", messageStrut)
			service.ChatRecordSave(messageStrut)
			client, ok := Manager.Clients[messageStrut.Recipient]
			//接收人不存在时，说明对方离线
			fmt.Println("所有链接", Manager.Clients)
			if !ok {
				fmt.Println("对方离线 消息内容", string(broadcast))
				offlinePrompt := &Message{
					Content:   "系统消息:对方暂时离线",
					Recipient: messageStrut.Sender, //返回给自己
					Sender:    -1,
				}
				marshal, err := json.Marshal(offlinePrompt)
				if err != nil {
					fmt.Println("json 解析 err", err)
				}
				meClient, _ := Manager.Clients[messageStrut.Sender] //发送给自己
				meClient.Send <- marshal                            //可以将离线数据写入其他地方，等待上线后主动拉取
			} else {
				select {
				case client.Send <- broadcast:
				default:
					client.Client.Close()
					delete(Manager.Clients, client.Id)
				}
			}

		}
	}

}
